# _*_ coding:utf-8 _*_
# at:2023-11-22
# author:zizle
import json
import datetime
import pathlib
import time
import threading
import pandas as pd
from ths_api import THSClientAPI
from server_api import ServerSystemAPI


class FuturesContract:
    def __init__(self, run_date: datetime.date):
        self.run_date = run_date


class AutomaticRun:
    def __init__(self, run_date: datetime.date = None):
        self.run_date = run_date if run_date else datetime.date.today()

    def read_futures_main_contract_configs(self, pointers: list = None, customer_defines: list = None):
        with open('configs/THS_品种主力合约行情.json', encoding='utf8', mode='r') as fp:
            indexes = json.load(fp)
        if pointers:
            indexes = list(filter(lambda x: x['source_id'] in pointers, indexes))

        local_indexes = {i['source_id']: i['ths_code'] for i in indexes}
        indicates = {i['source_id']: i['ths_indicate'] for i in indexes}

        customer_define_index = customer_defines if customer_defines else []
        customer_indexes = list(filter(lambda x: x['source_id'] in local_indexes.keys(), customer_define_index))
        for ci in customer_indexes:
            ci['ths_code'] = local_indexes.get(ci['source_id'])
            ci['ths_indicate'] = indicates.get(ci['source_id'])
            if not ci['ths_code'] or not ci['ths_indicate']:
                raise ValueError(f'{ci["name_zh"]}指标不存在！')
        return customer_indexes

    def read_option_volatility_configs(self, pointers: list = None, only_option: bool = False):
        with open('configs/波动率.json', 'r', encoding='utf8') as fp:
            indexes = json.load(fp)
        if pointers:
            indexes = list(filter(lambda x: x['source_id'] in pointers, indexes))
        if only_option:
            indexes = list(filter(lambda x: x['flag'] == 'us_impliedvol', indexes))
        return indexes

    def read_updated_config(self):
        update_file = pathlib.Path(f'configs/updated_{self.run_date.strftime("%Y%m%d")}.json')
        if not update_file.exists():
            return {}

        with open(update_file, 'r', encoding='utf8') as f:
            configs = json.load(f)
        return configs

    def set_updated_config(self, configs):
        update_file = pathlib.Path(f'configs/updated_{self.run_date.strftime("%Y%m%d")}.json')
        with open(update_file, 'w', encoding='utf8') as f:
            json.dump(configs, f)

    def run(self):
        server_api = ServerSystemAPI()
        custom_defines = server_api.get_customer_define_index_list()
        up_config = self.read_updated_config()
        with THSClientAPI() as ths_api:
            now = datetime.datetime.now().strftime("%H:%M")
            if now >= '15:50' and not up_config.get('fc_updated'):
                # 期货合约名称
                print(f'{datetime.datetime.now().strftime("%H:%M")} 开始更新期货合约数据')
                futures_contract = ths_api.get_futures_contract(run_date=self.run_date)
                server_api.save_futures_contract(futures_contract=futures_contract)
                up_config['fm_updated'] = True
            if now >= '15:50' and not up_config.get('ffm_updated'):
                print(f'{datetime.datetime.now().strftime("%H:%M")} 开始更新期货主力合约行情数据')
                # 期货主力合约行情
                main_contract_list = self.read_futures_main_contract_configs(customer_defines=custom_defines)
                t_count = len(main_contract_list)
                for i, fm in enumerate(main_contract_list, 1):
                    time.sleep(0.2)
                    ret_values = ths_api.get_history_quote(index_item=fm)
                    server_api.save_futures_main_quotes(sheet_id=fm['id'], datalist=ret_values)
                    print(f'\033[1;35m【{"%04d" % i}/{"%04d" % t_count}】{fm["name_zh"]},指标{fm["source_id"]},起始日期:{ret_values[0]["datadate"]}保存完成.\033[0m')
                up_config['ffm_updated'] = True
            if now >= '16:23':
                print(f'{datetime.datetime.now().strftime("%H:%M")} 开始更新期权波动率数据')
                # 期权波动率
                cover_dict = {
                    'AP.401': '403',
                    'C.2401': '2405',
                    'M.2401': '2405',
                    'PP.2401': '2405',
                    'P.2401': '2405',
                    'V.2401': '2405',
                    'L.2401': '2405',
                    'PG.2401': '2402',
                }
                main_contracts = server_api.get_variety_main_contract(run_date=self.run_date, cover_dict=cover_dict)
                for ov in self.read_option_volatility_configs(only_option=False):
                    time.sleep(0.2)
                    op_code = server_api.get_implied_option_code(ov, contracts_dict=main_contracts, run_date=self.run_date)
                    if op_code.endswith('.INE'):
                        op_code = op_code.replace('.INE', '.SHF')
                    if ov['flag'] == 'us_impliedvol':  # 平值期权隐含波动率
                        value = ths_api.get_implied_volatility(op_code, run_date=self.run_date)
                    elif ov['flag'] == 'volatilityratio':  # 标的历史波动率
                        # 基础数据-期权-标的历史波动率-iFinD数据接口
                        value = ths_api.get_history_volatility(op_code, run_date=self.run_date, day_count=ov["day_count"])
                    else:
                        raise ValueError('不支持的数据类型.')
                    if ov['source_id'] in ['R00020697', 'R00020698']:  # 动力煤的平值看涨或跌的期权隐含波动率为0
                        value = 0
                    if value is None:
                        print(f'\033[1;36m{op_code},{ov["name_zh"]} {self.run_date}的数据为None.{ov["source_id"]}\033[0m')
                        continue
                    server_api.save_index_data(sheet_id=ov['id'],
                                               datalist=[{'datadate': self.run_date.strftime('%Y-%m-%d'), 'datavalue': value}])
                    print(f'\033[1;35m{op_code},{ov["name_zh"]} {self.run_date}={value}保存完成.\033[0m')
            self.set_updated_config(up_config)
            # 指标更新
            frequency_list = ['日'] if now >= '16:58' else ['日', '周']
            for f in frequency_list:
                ths_indexes = server_api.get_ths_index_list(frequency=f, pointers=None)
                print(f'{datetime.datetime.now().strftime("%H:%M")} 开始更新{f}指标数据, 数量:{len(ths_indexes)}')
                t_count = len(ths_indexes)
                for i, index_item in enumerate(ths_indexes, 1):
                    time.sleep(0.2)
                    start = index_item["enddate"] if index_item["enddate"] else index_item["startdate"]
                    end = datetime.datetime.today().strftime('%Y-%m-%d')
                    # 整理保存数据
                    table_values = ths_api.get_edb(index_item["source_id"], start, end)
                    if not table_values or len(table_values) == 1:
                        print(f'\033[1;36m【{"%04d" % i}/{"%04d" % t_count}】{index_item["source_id"]}【{index_item["name_zh"]}】,起始日期:{start}已存,略...\033[0m')
                        continue
                    ret_df = pd.DataFrame(table_values, columns=['datadate', 'datavalue'])
                    # 检验date格式
                    ret_df['datadate'] = ret_df['datadate'].apply(lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').strftime('%Y-%m-%d'))
                    ret_df['datavalue'] = pd.to_numeric(ret_df['datavalue'])
                    ret_df['datavalue'] = ret_df['datavalue'].astype(float)
                    datalist = ret_df.to_dict(orient='records')
                    code = server_api.save_index_data(sheet_id=index_item['id'], datalist=datalist)
                    if not code or code != 200:
                        print(f'\033[1;34mTHS指标{index_item["source_id"]}【{index_item["name_zh"]}】,起始日期:{start}保存失败了\033[0m')
                    else:
                        values = [v for v in datalist if v['datadate'] > start]
                        print(f'\033[1;35m【{"%04d" % i}/{"%04d" % t_count}】{index_item["source_id"]}【{index_item["name_zh"]}】,起始日期:{start},values={values}保存完成.\033[0m')
            print(f'{now}~{datetime.datetime.now().strftime("%H:%M")}本轮程序运行完毕!')


while True:
    if datetime.datetime.now().strftime('%H:%M') in ['15:35', '15:56', '16:23', '16:58']:
        AutomaticRun(run_date=None).run()
    time.sleep(20)
